package top.lishuoboy.spring.aop.spring_aspects;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

// 2.增强的类
@Slf4j
@Component
@Aspect
public class Student20Proxy {
    /**
     * 切入点 表达式。
     * execution([权限修饰符] [返回类型] [类全路径] [方法名称] ([参数列表]))
     *
     * 举例1：对 com.zhh.dao.BookDao 类里的 add 进行增强
     * execution(* com.zhh.dao.BookDao.add(..))
     * 举例2：对 com.zhh.dao.BookDao 类里的所有方法进行增强
     * execution(* com.zhh.dao.BookDao.*(..))
     * 举例3：对 com.zhh.dao 包里的所有类，类里的所有方法进行增强
     * execution(* com.zhh.dao..*(..))
     */

    /** 抽取相同的切入点，public。所有切面都用 */
    @Pointcut("execution(* top.lishuoboy.spring.aop.spring_aspects.Student20.add(..))")
    public void myCommonPointcut() {
    }

    /** 抽取相同的切入点,private。自己使用 */
    @Pointcut("execution(* top.lishuoboy.spring.aop.spring_aspects.Student20.add(..))")
//    @Pointcut("myCommonPointcut()")
    private void myPointcut() {
    }

    @Around(value = "myPointcut()")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        log.warn("前置环绕通知");
        // 被增强的方法执行
        proceedingJoinPoint.proceed();
        log.warn("后置环绕通知");  // 有异常时不执行
    }

    @Before(value = "myPointcut()")
    public void before() {
        log.warn("前置通知");
    }

    /** 返回通知，无异常时执行，与“异常通知”互斥。pointcut 与 value 一样，pointcut 优先级高 */
//    @AfterReturning(value = "execution(* top.lishuoboy.spring.aop.spring_aspects.Student20.add(..))", pointcut = "")  // 单独定义切入点，不用抽取的相同切入点也可以
    @AfterReturning(value = "myPointcut()", pointcut = "")
    public void afterReturning() {
        log.warn("返回通知");
    }

    /** 异常通知，有异常时执行，与“返回通知”互斥。pointcut 与 value 一样，pointcut 优先级高 */
    @AfterThrowing(value = "myPointcut()", pointcut = "")
    public void afterThrowing() {
        log.warn("异常通知");
    }

    @After(value = "myPointcut()")
    public void after() {
        log.warn("后置通知");  // 后置通知（最终通知），有没有异常都会执行，类似 finally
    }
}